package com.kajespero.webapp.controller.commons;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.servlet.ModelAndView;

import com.kajespero.json.Converter.JSonConverter;
import com.kajespero.model.IdentifierVOBean;
import com.kajespero.model.UserBean;
import com.kajespero.service.commons.Service;
import com.kajespero.service.user.UserService;
import com.kajespero.service.user.impl.UserServiceImpl;
import com.kajespero.vo.UserVO;
import com.kajespero.vo.VO;
import com.kajespero.webapp.editor.annotation.process.PropertyEditorSupportAnnotationProcess;
import com.kajespero.webapp.validator.annotation.process.ValidatorAnnotationProcess;
import com.kajespero.webapp.validator.commons.IValidator;

@SuppressWarnings("rawtypes")
public abstract class AbstractController<S extends Service, T extends IdentifierVOBean<?>> {
	
	private static final Log LOG = LogFactory.getLog(AbstractController.class);
	
	private static final UserService USER_SERVICE = new UserServiceImpl();
	
	private S service;
	
	private Class<T> clazzBean;

	public AbstractController(){
		this.initService();
	}
	
	@SuppressWarnings("unchecked")
	private void initService(){
		ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
		LOG.debug("class test == " + getClass());
		Class<S> clazz = (Class<S>) parameterizedType.getActualTypeArguments()[0];
		clazzBean = (Class<T>) parameterizedType.getActualTypeArguments()[1];
		try {
			service = (S) clazz.newInstance();
		} catch (InstantiationException e) {
			LOG.error("InstantiationException " + e.getMessage(), e);
		} catch (IllegalAccessException e) {
			LOG.error("IllegalAccessException " + e.getMessage(), e);
		}
	}
	
	public S getService(){
		return this.service;
	}
	
	public void mergeUsers(List<UserVO> users, UserVO newUser){
		if(users.isEmpty()){
			users.add(newUser);
			return;
		}
		else {
			int i;
			for(i=0; i < users.size(); i++){
				UserVO user = users.get(i);
				if(user.getId().intValue() == newUser.getId().intValue()){
					users.set(i, newUser);
					break;
				}
			}
		}
	}
	
	
	@InitBinder
	private void initBinder(ServletRequestDataBinder binder){
		VO result = (VO) binder.getTarget();
		PropertyEditorSupportAnnotationProcess.register(binder, result);
	}
	
	
	public void validBinding(BindingResult result){
		VO resultVo = (VO) result.getTarget();
		IValidator<?> validator = ValidatorAnnotationProcess.getValidator(resultVo);
		validator.validate(resultVo, result);
	}
	
	public boolean checkCredential(Map<String, Serializable> map){
		if(map == null || map.isEmpty()){
			return false;
		}
		else {
			String login = (String) map.get("login");
			String password = (String) map.get("password");
			UserBean admin = USER_SERVICE.findByAuthentificate(login, password);
			return admin != null;
		}
	}
	
	public T convertJsonObject(Map<String, Serializable> map){
		return JSonConverter.fromJSonObject(map, clazzBean);
	}

	public abstract ModelAndView create();
	
	public abstract ModelAndView update(HttpServletRequest request);
	
	public abstract void delete(HttpServletRequest request);
	
	public abstract void saveOrUpdate(T instance, BindingResult result,HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}
